import { forEach } from './utils'

const regTagStartBlock = /^<(?<tagName>[a-z0-9]+)(?<tagAttrsStr>.*?)>/i
const regTagEndBlock = /<\/[a-z0-9]+>/i
const regEmptyBlock = /^( |\n)+/i
const regAttrBlock =
  /(?<attrName>[@:\-a-z0-9]+)=('|")(?<attrValue>[a-z0-9:;\-]+)\2|(?<attrName2>[a-z0-9\-]+)/i
const regMustache = /\{\{(?<reactiveName>[a-z0-9]+)\}\}/i
class Compiler {
  parse(html) {
    let root = null
    const stack = []
    while (html) {
      const emptyBlock = html.match(regEmptyBlock)
      if (emptyBlock) {
        html = this.go(html, emptyBlock.index + emptyBlock[0].length)
      }
      const tagEndBlock = html.match(regTagEndBlock)
      const tagStartBlock = html.match(regTagStartBlock)
      const parent = stack[stack.length - 1]
      if (tagStartBlock) {
        let { tagName, tagAttrsStr } = tagStartBlock.groups
        html = this.go(html, tagStartBlock.index + tagStartBlock[0].length)
        let attrMatch = tagAttrsStr.match(regAttrBlock)
        const astNode = {
          tagName: null,
          attrs: {},
          props: {},
          listener: {},
          children: [],
          directive: {}
        }
        while (attrMatch) {
          const { attrName, attrValue, attrName2 } = attrMatch.groups
          const attr = attrName2
            ? { [attrName2]: true }
            : { [attrName]: attrValue }
          forEach(attr, (val, key) => {
            if (key.startsWith(':')) {
              astNode.props[key.slice(1)] = val
            } else if (key.startsWith('@')) {
              astNode.listener[key.slice(1)] = val
            } else if (key.startsWith('v-')) {
              astNode.directive[key.slice(2)] = val
            } else {
              astNode.attrs[key] = val
            }
          })
          tagAttrsStr = this.go(tagAttrsStr, attrMatch[0].length)
          attrMatch = tagAttrsStr.match(regAttrBlock)
        }
        astNode.tagName = tagName
        if (!parent) {
          root = astNode
        } else {
          parent.children.push(astNode)
        }
        stack.push(astNode)
      } else if (tagEndBlock) {
        if (tagEndBlock.index > 0) {
          let text = html.substring(0, tagEndBlock.index)
          let mustacheMatch = text.match(regMustache)
          while (mustacheMatch) {
            if (mustacheMatch.index > 0) {
              parent.children.push({
                tagName: 'text',
                value: text.substring(0, mustacheMatch.index)
              })
            }
            if (mustacheMatch.groups) {
              parent.children.push({
                tagName: 'text',
                value: mustacheMatch.groups.reactiveName,
                reactive: true
              })
            }
            text = this.go(text, mustacheMatch.index + mustacheMatch[0].length)
            mustacheMatch = text.match(regMustache)
          }
          if (text) {
            parent.children.push({
              tagName: 'text',
              value: text
            })
          }
          html = this.go(html, tagEndBlock.index)
        } else {
          stack.pop()
          html = this.go(html, tagEndBlock[0].length)
        }
      }
    }
    console.log(root)
    return root
  }
  go(html, length) {
    return html.substring(length)
  }
}

export default Compiler
